//
// Created by Yun Zeng on 2018/4/12.
// HomeMaster 工程驱动程序
// OLED 433(CC1101) INFRARED
//

#include "master.h"
#include "platform.h"

static master_dev_typedef master_dev;

// /dev/master 读写操作
static int master_open(struct inode *pinode, struct file *pfile) {
    printk(MASTER_DEV_NAME ": open\n");
    platform_open();
    return 0;
}

static int master_release(struct inode *pinode, struct file *pfile) {
    printk(MASTER_DEV_NAME ": release\n");
    platform_close();
    return 0;
}

static ssize_t master_read(struct file *pfile, char __user *buf, size_t size, loff_t *ppos) {
    ssize_t len = size;
    uint8_t buffer[len];

    len = platform_read(buffer, len);
    if (len < 0) {
        printk(MASTER_DEV_NAME " read error(%d)\n", len);
        return 0;
    } else {
        //printk(MASTER_DEV_NAME " read rev_count(%d)\n", size);
    }

    if (copy_to_user(buf, buffer, len)) {
        ssize_t result = -EFAULT;
        printk(MASTER_DEV_NAME ": copy_to_user failed\n");
        return result;
    }

    return len;
}

static ssize_t master_write(struct file *pfile, const char __user *buf, size_t size, loff_t *ppos) {
    ssize_t  len = size;
    static uint8_t buffer[1024*9];  // 临时解决OLED显示数据写入问题

    if (len > sizeof(buffer)) {
        return -1;
    }

//    printk(MASTER_DEV_NAME " write len(%d)\n", size);
    memset(buffer, 0x00, size);
    if (copy_from_user(buffer, buf, size)) {
        ssize_t result = -EFAULT;
        printk(MASTER_DEV_NAME " copy_from_user failed\n");
        return result;
    }
    platform_write(buffer, len);
//
//    {
//        char log_buffer[size*2+1];
//        int i=0;
//        for (i=0; i<size; i++) {
//            sprintf(&log_buffer[2*i], "%02x", buffer[i]);
//        }
//        printk(MASTER_DEV_NAME " write(%d): %s\n", size, log_buffer);
//    }
    return len;
}

static const struct file_operations master_fops = {
        .owner = THIS_MODULE,
        .open = master_open,
        .release = master_release,
        .read = master_read,
        .write = master_write,
};

// 驱动模块部分
static int __init master_init(void) {
    int result = -1;
    printk(MASTER_DEV_NAME ": init()\n");

    // request device
    master_dev.devno = MKDEV(MASTER_DEV_MAJOR, MASTER_DEV_MINOR);
    result = register_chrdev_region(master_dev.devno, 1, MASTER_DEV_NAME);
    if (result < 0) {
        printk(MASTER_DEV_NAME ": register_chrdev_region() failed\n");
        return result;
    }

    // register device
    cdev_init(&master_dev.cdev, &master_fops);
    master_dev.cdev.owner = THIS_MODULE;
    result = cdev_add(&master_dev.cdev, master_dev.devno, 1);
    if (result < 0) {
        unregister_chrdev_region(master_dev.devno, 1);
        printk(MASTER_DEV_NAME ": add cdev err\n");
        return -1;
    }

    // create class
    master_dev.pclass = class_create(THIS_MODULE, MASTER_DEV_NAME);
    if (IS_ERR(master_dev.pclass)) {
        cdev_del(&master_dev.cdev);
        unregister_chrdev_region(master_dev.devno, 1);
        printk(MASTER_DEV_NAME ": class_create() failed\n");
        return -1;
    }

    // device node
    device_create(master_dev.pclass, NULL, master_dev.devno, NULL, MASTER_DEV_NAME);
    printk(MASTER_DEV_NAME ": module initialization ok\n");

    platform_init(&master_dev);

    return 0;
}

static void __exit master_exit(void) {
    platform_exit(&master_dev);

    device_destroy(master_dev.pclass, master_dev.devno);
    class_destroy(master_dev.pclass);
    cdev_del(&master_dev.cdev);
    unregister_chrdev_region(master_dev.devno, 1);
    printk(MASTER_DEV_NAME ": module exit\n");
}

module_init(master_init);
module_exit(master_exit);

MODULE_VERSION("v0.0.1");
MODULE_AUTHOR("yun <zyclouds@gmail.com>");
MODULE_LICENSE("Dual BSD/GPL");






